package org.zjt.ref;

import org.zjt.collections.WeakHashMapTest;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.WeakHashMap;

/**
 * 1、引用类型
 *
 *      强引用：一般引用
 *      软引用：当内存紧张时候回被gc
 *      弱引用：当经历gc后，对象会被gc
 *      虚引用：不能得到对象，类似于finalizer时期的对象。
 *
 *
 * 2、ReferenceQueue: 当一个被gc的对象被gc后，会存放到ref队列中。
 *
 *      当一个对象被gc掉的时候通知用户线程，进行额外的处理时，就需要使用引用队列了。
 *      ReferenceQueue即这样的一个对象，当一个obj被gc掉之后，其相应的包装类，即ref对象会被放入queue中。我们可以从queue中获取到相应的对象信息，同时进行额外的处理。比如反向操作，数据清理等。
 *
 * 3、在类weakHashMap中的使用ReferenceQueue,监控weakedkey的变化。
 *
 *      weakHashMap即使用weakReference当作key来进行数据的存储，当key中的引用被gc掉之后，它会自动(类似自动)的方式将相应的entry给移除掉，即我们会看到size发生了变化。
 *      当key丢失后，在get、put、size 等操作，weakHashMap会删除掉所有的value。
 *      （weak引用，当对象强引用丢失后，该weak就会gc。）
 *
 */
public class RefQueue {

    private static final int _1M = 1 << 20;

    public static void main(String[] args) throws InterruptedException {

        // 监控内存是的gc情况：当weak对象被gc后，会通过观察者模式来得到gc的对象
        ReferenceQueue referenceQueue =new ReferenceQueue();
        Object value = new Object();
        Map<Object, Object> map = new HashMap<>();
        for(int i = 0;i < 10000;i++) {
            byte[] bytes = new byte[_1M];
            WeakReference<byte[]> weakReference = new WeakReference<byte[]>(bytes, referenceQueue);
            map.put(weakReference, value);
        }
        System.out.println("map.size->" + map.size());


        //得到gc对象事件
        Thread thread = new Thread(() -> {
            try {
                int cnt = 0;
                WeakReference<byte[]> k;
                while((k = (WeakReference) referenceQueue.remove()) != null) {
                    System.out.println((cnt++) + "回收了:" + k);
                    map.remove(k);
                }
            } catch(InterruptedException e) {
                //结束循环
            }
        });
        thread.setDaemon(true);
        thread.start();
        Thread.currentThread().sleep(100000000);
    }
}
